package gateway.server.http;

import gateway.api.engine.Engine;
import gateway.internal.api.message.DefaultHttpMessage;
import gateway.server.util.StringUtil;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Jin Zheng
 * @since 1.0 2020-09-10
 */
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>
{
	private static Logger logger = LoggerFactory.getLogger(HttpServerHandler.class);
	public static final String PARAM_SPLIT = ",";

	private final String id;
	private final Engine engine;

	public HttpServerHandler(String id, Engine engine)
	{
		this.id = id;
		this.engine = engine;
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception
	{
		logger.info("Receive http, uri: {}, method: {}", request.uri(), request.method());
		DefaultHttpMessage message = this.parseMessage(request);

		engine.dispatch(id, message);

		this.send(ctx);
	}

	private DefaultHttpMessage parseMessage(FullHttpRequest request)
	{
		DefaultHttpMessage message = new DefaultHttpMessage();
		QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
		message.setUrl(decoder.path());
		message.setMethod(request.method().name());
		byte[] bytes = new byte[request.content().readableBytes()];
		request.content().readBytes(bytes);
		message.setByteArray(bytes);

		Map<String, String> queryMap = new HashMap<>();
		for (Map.Entry<String, List<String>> entry : decoder.parameters().entrySet())
		{
			String value = StringUtil.join(entry.getValue(), PARAM_SPLIT);
			queryMap.put(entry.getKey(), value);
		}
		message.setQueryMap(Map.copyOf(queryMap));

		Map<String, String> map = new HashMap<>();
		for (Map.Entry<String, String> header : request.headers())
		{
			map.put(header.getKey(), header.getValue());
		}
		message.setHeaderMap(Map.copyOf(map));
		message.setPathMap(new HashMap<>());
		return message;
	}

	private void send(ChannelHandlerContext ctx)
	{
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
				HttpResponseStatus.valueOf(202));
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}


	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
	{
		super.exceptionCaught(ctx, cause);
		logger.error("Error,", cause);
	}
}
